<?php

namespace  addons\qingdongams\library;

use addons\qingdongams\model\Staff;
use addons\qingdongams\library\Token;
use app\common\model\User;
use fast\Random;
use think\Config;
use think\Db;
use think\Exception;
use think\Hook;
use think\Request;
use think\Validate;

class StaffAuth {
    protected static $instance = null;
    protected        $_error   = '';
    protected        $_logined = false;
    protected        $_user    = null;
    protected        $_token   = '';
    //Token默认有效时长
    protected $keeptime   = 86400*30;
    protected $requestUri = '';
    protected $rules      = [];
    //默认配置
    protected $config      = [];
    protected $options     = [];
    protected $allowFields = ['id', 'name', 'username', 'nickname', 'department_id','mobile', 'img', 'num','role','parent_id','group_ids'];


    public function __construct($options = []) {
        if ($config = Config::get('user')) {
            $this->config = array_merge($this->config, $config);
        }
        $this->options = array_merge($this->config, $options);
    }


    /**
     * @param array $options 参数
     * @return Auth
     */
    public static function instance($options = []) {
        if (is_null(self::$instance)) {
            self::$instance = new static($options);
        }

        return self::$instance;
    }


    /**
     * 获取User模型
     * @return User
     */
    public function getUser() {
        return $this->_user;
    }


    /**
     * 兼容调用user模型的属性
     * @param string $name
     * @return mixed
     */
    public function __get($name) {
        return $this->_user ? $this->_user->$name : null;
    }


    /**
     * 根据Token初始化
     * @param string $token Token
     * @return boolean
     */
    public function init($token) {
        if ($this->_logined) {
            return true;
        }
        if ($this->_error) {
            return false;
        }
        $data = Token::get($token,false,$this->options);
        if (!$data) {
            return false;
        }
        $login_id = trim($data['login_id']);
        $login_id = intval(substr($login_id, 5));
        if ($login_id) {
            $staff = Staff::get($login_id);
            if (!$staff) {
                $this->setError('Account not exist');

                return false;
            }
            $this->_user    = $staff;
            $this->_logined = true;
            $this->_token   = $token;

            //初始化成功的事件
            Hook::listen("user_init_successed", $this->_user);

            return true;
        } else {
            $this->setError('You are not logged in');

            return false;
        }
    }

    /**
     * 用户登录
     *
     * @param string $account  账号,用户名、邮箱、手机号
     * @param string $password 密码
     * @return boolean
     */
    public function login($account, $password)
    {
        $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'mobile');
        $staff = Staff::get([$field => $account]);
        if (!$staff) {
            $this->setError('Account is incorrect');
            return false;
        }

        if ($staff->status != 1) {
            $this->setError('Account is locked');
            return false;
        }
        if ($staff->password != $this->getEncryptPassword($password, $staff->salt)) {
            $this->setError('Password is incorrect');
            return false;
        }

        //直接登录会员
        $this->direct($staff->id);

        return true;
    }

    /**
     * 注册用户
     * @param string $nickname 用户名
     * @param string $mobile 手机号
     * @param array $extend 扩展参数
     * @return boolean
     */
    public function register($nickname, $mobile = '', $extend = []) {
        $data = [
            'nickname' => $nickname,
            'mobile'   => $mobile,
        ];

        $params = array_merge($data, [
            'status' => 1
        ]);
        $params = array_merge($params, $extend);
        //账号注册时需要开启事务,避免出现垃圾数据
        Db::startTrans();
        try {
            $staff = Staff::create($params, true);

            $this->_user = Staff::get($staff->id);

            //设置Token
            $this->_token = Random::uuid();
            Token::set($this->_token, 'staff' . $staff->id, $this->keeptime, $this->options);

            //设置登录状态
            $this->_logined = true;

            //注册成功的事件
            Hook::listen("staff_register_successed", $this->_user, $data);
            Db::commit();
        } catch (Exception $e) {
            $this->setError($e->getMessage());
            Db::rollback();

            return false;
        }

        return true;
    }


    /**
     * 直接登录账号
     * @param int $staff_id
     * @return boolean
     */
    public function direct($staff_id) {
        $staff = Staff::get($staff_id);
        if ($staff) {
            Db::startTrans();
            try {
                $this->_user  = $staff;
                $this->_token = Random::uuid();
                Token::set($this->_token, 'staff' . $staff->id, $this->keeptime,$this->options);

                $this->_logined = true;

                //登录成功的事件
                Hook::listen("staff_login_successed", $this->_user);
                Db::commit();
            } catch (Exception $e) {
                Db::rollback();
                $this->setError($e->getMessage());

                return false;
            }

            return true;
        } else {
            return false;
        }
    }


    /**
     * 退出
     * @return boolean
     */
    public function logout() {
        if (!$this->_logined) {
            $this->setError('You are not logged in');

            return false;
        }
        //设置登录标识
        $this->_logined = false;
        //删除Token
        Token::delete($this->_token,$this->options);
        //退出成功的事件
        Hook::listen("staff_logout_successed", $this->_user);

        return true;
    }


    /**
     * 判断是否登录
     * @return boolean
     */
    public function isLogin() {
        if ($this->_logined) {
            return true;
        }

        return false;
    }


    /**
     * 获取当前Token
     * @return string
     */
    public function getToken() {
        return $this->_token;
    }


    /**
     * 获取员工基本信息
     */
    public function getUserinfo() {
        $data                  = $this->_user->toArray();
        $allowFields           = $this->getAllowFields();
        $userinfo              = array_intersect_key($data, array_flip($allowFields));
        $userinfo              = array_merge($userinfo, Token::get($this->_token,$this->options));
        $group_ids=explode(',',$userinfo['group_ids']);
        $userinfo['role_type'] = 1;//基础和团队
        if (in_array(1, $group_ids)) {//超级管理员
            $userinfo['role_type'] = 9;
        }
        return $userinfo;
    }


    /**
     * 获取当前请求的URI
     * @return string
     */
    public function getRequestUri() {
        return $this->requestUri;
    }


    /**
     * 设置当前请求的URI
     * @param string $uri
     */
    public function setRequestUri($uri) {
        $this->requestUri = $uri;
    }


    /**
     * 获取允许输出的字段
     * @return array
     */
    public function getAllowFields() {
        return $this->allowFields;
    }


    /**
     * 设置允许输出的字段
     * @param array $fields
     */
    public function setAllowFields($fields) {
        $this->allowFields = $fields;
    }


    /**
     * 获取密码加密后的字符串
     * @param string $password 密码
     * @param string $salt 密码盐
     * @return string
     */
    public function getEncryptPassword($password, $salt = '') {
        return md5(md5($password) . $salt);
    }


    /**
     * 检测当前控制器和方法是否匹配传递的数组
     * @param array $arr 需要验证权限的数组
     * @return boolean
     */
    public function match($arr = []) {
        $request = Request::instance();
        $arr     = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr) {
            return false;
        }
        $arr = array_map('strtolower', $arr);
        // 是否存在
        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) {
            return true;
        }

        // 没找到匹配
        return false;
    }


    /**
     * 设置会话有效时间
     * @param int $keeptime 默认为永久
     */
    public function keeptime($keeptime = 0) {
        $this->keeptime = $keeptime;
    }


    /**
     * 设置错误信息
     * @param $error 错误信息
     * @return Auth
     */
    public function setError($error) {
        $this->_error = $error;

        return $this;
    }


    /**
     * 获取错误信息
     * @return string
     */
    public function getError() {
        return $this->_error ? __($this->_error) : '';
    }
    /**
     * 修改密码
     * @param string $newpassword       新密码
     * @param string $oldpassword       旧密码
     * @param bool   $ignoreoldpassword 忽略旧密码
     * @return boolean
     */
    public function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false)
    {
        if (!$this->_logined) {
            $this->setError('你当前还未登录');
            return false;
        }
        //判断旧密码是否正确
        if ($this->_user->password == $this->getEncryptPassword($oldpassword, $this->_user->salt) || $ignoreoldpassword) {
            Db::startTrans();
            try {
                $salt = Random::alnum();
                $newpassword = $this->getEncryptPassword($newpassword, $salt);
                Staff::where(['id'=>$this->_user->id])->update([
                    'password' => $newpassword,
                    'salt' => $salt,
                ]);

                Token::delete($this->_token);
                //修改密码成功的事件
                Db::commit();
            } catch (Exception $e) {
                Db::rollback();
                $this->setError($e->getMessage());
                return false;
            }
            return true;
        } else {
            $this->setError('旧密码不正确');
            return false;
        }
    }
}
